package com.visionblue.business.ship.util;

import android.util.Log;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

/**
 * @author: xlh
 * @date: 2020-05-28 2:04 PM
 * @desc:
 */
public class MLog {

    private static volatile Logger logger = new DefaultLogger();

    public interface Logger {
        void d(@NonNull String message, @NonNull Object... args);

        void d(@Nullable Throwable throwable, @NonNull String message, @NonNull Object... args);

        void e(@NonNull String message, @NonNull Object... args);

        void e(@Nullable Throwable throwable, @NonNull String message, @NonNull Object... args);
    }

    private static class NoLogger implements Logger {
        @Override
        public void d(@NonNull String message, @NonNull Object... args) {
        }

        @Override
        public void d(@Nullable Throwable throwable, @NonNull String message, @NonNull Object... args) {
        }

        @Override
        public void e(@NonNull String message, @NonNull Object... args) {

        }

        @Override
        public void e(@Nullable Throwable throwable, @NonNull String message, @NonNull Object... args) {

        }
    }

    private static class DefaultLogger implements Logger {
        DefaultLogger() {
        }

        @Override
        public void d(@NonNull String message, @NonNull Object... args) {
            String formatted = String.format(message, args);
            if (formatted.length() < 4000) {
                Log.d("MLog", formatted);
            } else {
                String[] lines = formatted.split("\n", -1);
                for (String line : lines) {
                    Log.d("MLog", line);
                }
            }
        }

        @Override
        public void d(@Nullable Throwable throwable,
                      @NonNull String message,
                      @NonNull Object... args) {
            d(String.format(message, args) + '\n' + Log.getStackTraceString(throwable));
        }

        @Override
        public void e(@NonNull String message, @NonNull Object... args) {
            String formatted = String.format(message, args);
            if (formatted.length() < 4000) {
                Log.e("MLog", formatted);
            } else {
                String[] lines = formatted.split("\n", -1);
                for (String line : lines) {
                    Log.e("MLog", line);
                }
            }
        }

        @Override
        public void e(@Nullable Throwable throwable, @NonNull String message, @NonNull Object... args) {
            e(String.format(message, args) + '\n' + Log.getStackTraceString(throwable));
        }
    }

    public static void setLogger(@Nullable Logger logger) {
        MLog.logger = logger;
    }

    public static void setNoLog() {
        setLogger(new NoLogger());
    }

    public static void d(@NonNull String message, @NonNull Object... args) {
        // Local variable to prevent the ref from becoming null after the null check.
        Logger logger = MLog.logger;
        if (logger == null) {
            return;
        }
        logger.d(message, args);
    }

    public static void e(@NonNull String message, @NonNull Object... args) {
        Logger logger = MLog.logger;
        if (logger == null) {
            return;
        }
        logger.e(message, args);
    }

    public static void d(@Nullable Throwable throwable,
                         @NonNull String message,
                         @NonNull Object... args) {
        // Local variable to prevent the ref from becoming null after the null check.
        Logger logger = MLog.logger;
        if (logger == null) {
            return;
        }
        logger.d(throwable, message, args);
    }

    private MLog() {
        throw new AssertionError();
    }
}
